# coding=utf-8
import datetime
import logging

from sqlalchemy import func

from common import orm
from common.bank_record.model import BankRecord, RECORD_STATUS
from common.bankcard.model import BankCard, BANKCARD_TYPE
from common.utils.db import list_object, get, upsert, generate_filter, \
    parse_query_dct, get_count, get_orderby, paginate
from common.utils.decorator import sql_wrapper

_LOGGER = logging.getLogger('hydra')


@sql_wrapper
def get_bank_record(id):
    return get(BankRecord, id)


@sql_wrapper
def upsert_bank_record(info, id=None):
    return upsert(BankRecord, info, id)


@sql_wrapper
def list_bank_record(query_dct):
    return list_object(query_dct, BankRecord)

@sql_wrapper
def list_bank_record_card_type(query_dct, card_type):
    query_dct = parse_query_dct(query_dct, BankRecord)
    query = orm.session.query(BankRecord) \
            .join(BankCard, BankRecord.bankcard_name == BankCard.name) \
            .filter(BankCard.type == card_type) \
            .filter(generate_filter(query_dct, BankRecord))

    total_count = get_count(query)
    orderby = get_orderby(query_dct.get('$orderby'), BankRecord)
    if orderby is not None:
        query = query.order_by(orderby)

    query = paginate(query, query_dct)

    return query.all(), total_count


@sql_wrapper
def get_bank_record_overview(parsed_dct):
    query = orm.session.query(func.sum(BankRecord.amount))
    query = query.filter(generate_filter(parsed_dct, BankRecord))
    income = query.filter(BankRecord.type == BANKCARD_TYPE.RECHARGE).scalar()
    spend = query.filter(BankRecord.type == BANKCARD_TYPE.PAYMENT).scalar()
    return income, spend


@sql_wrapper
def get_bank_record_overview_card_type(parsed_dct, card_type):
    query = orm.session.query(func.sum(BankRecord.amount)) \
            .join(BankCard, BankRecord.bankcard_name == BankCard.name) \
            .filter(BankCard.type == card_type) \
            .filter(generate_filter(parsed_dct, BankRecord))
    income = query.filter(BankRecord.type == BANKCARD_TYPE.RECHARGE).scalar()
    spend = query.filter(BankRecord.type == BANKCARD_TYPE.PAYMENT).scalar()
    return income, spend


@sql_wrapper
def get_last_card_transaction_time(bankcard_name):
    bank_record = BankRecord.query.filter(BankRecord.bankcard_name == bankcard_name).order_by(
        BankRecord.transaction_time.desc()).first()
    if bank_record:
        return bank_record.transaction_time
    else:
        return None


@sql_wrapper
def insert_bank_record(info, bank_card, status=RECORD_STATUS.UNMATCH):
    exist = BankRecord.query.filter(BankRecord.bankcard_name == bank_card.name).filter(
        BankRecord.detail == info['detail']).first()
    if exist:
        _LOGGER.info('bank_record_repeat, %s, %s, %s, %s, %s', bank_card.name,
                     info['transaction_time'].strftime('%Y-%m-%d %H:%M:%S'), info['amount'], info['balance'], info['detail'])
        return

    bank_record = BankRecord()
    bank_record.bankcard_name = bank_card.name
    bank_record.mch_id = bank_card.mch_id
    bank_record.bankcard_num = bank_card.account_number
    bank_record.bank = bank_card.bank
    bank_record.detail = info['detail']
    bank_record.payer = info['payer']
    bank_record.transfer_from = info['transfer_from']
    bank_record.transfer_to = info['transfer_to']
    bank_record.trading_channel = info['trading_channel']
    bank_record.amount = info['amount']
    bank_record.balance = info['balance']
    bank_record.remarks = info['remarks']
    bank_record.notes = info['notes']
    bank_record.transaction_time = info['transaction_time']
    bank_record.status = status

    if 'order_id' in info:
        bank_record.order_id = info['order_id']

    if info.get('type'):
        bank_record.type = info['type']
    bank_record.save()

    return bank_record.id


@sql_wrapper
def match_record(record_id, order_id):
    bank_record = BankRecord.query.filter(BankRecord.id == record_id).filter(
        BankRecord.status == RECORD_STATUS.UNMATCH).first()
    if not bank_record:
        return
    bank_record.order_id = int(order_id)
    bank_record.status = RECORD_STATUS.MATCHED
    bank_record.remarks = 'manual'
    bank_record.save()


@sql_wrapper
def get_bank_record_list_by_today(bankcard_name):
    now = datetime.datetime.now()
    zero_today = now - datetime.timedelta(hours=now.hour, minutes=now.minute, seconds=now.second,
                                          microseconds=now.microsecond)
    bank_record = BankRecord.query.filter(BankRecord.bankcard_name == bankcard_name).\
        filter(BankRecord.transaction_time >= zero_today).all()

    return bank_record


@sql_wrapper
def get_max_cash_flow_by_card_name(card_name):
    now = datetime.datetime.now()
    zero_today = now - datetime.timedelta(hours=now.hour, minutes=now.minute, seconds=now.second,
                                          microseconds=now.microsecond)
    positive_amount = orm.session.query(func.sum(BankRecord.amount)).filter(BankRecord.bankcard_name == card_name)\
        .filter(BankRecord.amount >= 0).filter(BankRecord.transaction_time >= zero_today).scalar()
    negative_amount = orm.session.query(func.sum(BankRecord.amount)).filter(BankRecord.bankcard_name == card_name)\
        .filter(BankRecord.amount < 0).filter(BankRecord.transaction_time >= zero_today).scalar()
    sum_amount = (positive_amount or 0) - (negative_amount or 0)
    return sum_amount
